package edu.purdue.cs.aggr.message;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.ConnectException;
import java.net.Socket;
import java.util.HashMap;

import edu.purdue.cs.aggr.Controller;
import edu.purdue.cs.aggr.Logger;

public class MessageSender {

	HashMap<String, ObjectOutputStream> streams = new HashMap<String, ObjectOutputStream>();
	private static String PORT_IP_SEPERATOR = ":";
	private String currentVertex = null;
	
	private static long firstSetupSent = -1;
	
	public MessageSender(String currentVertex) {
		this.currentVertex = currentVertex;
	}
	
	public synchronized void sendMessage (Message message, String destinationId) {
	  Logger.log(currentVertex, "Sending msg to : " + Controller.getIndexOf(destinationId) + " (" + destinationId + ") at " + System.currentTimeMillis());
		
		if ((message instanceof VertexSetupMessage) && (firstSetupSent < 0)) {
			firstSetupSent = System.currentTimeMillis();
		} else if ((message instanceof VertexSetupMessage) && (firstSetupSent >= 0)) {
//			System.out.println("Setup message send gap :" + (System.currentTimeMillis()-firstSetupSent));
		}
		
		if(message.getSender() == null)
		  message.setSender(currentVertex);
		try {
			ObjectOutputStream stream = streams.get(destinationId);
			if(stream==null) {
				createNewSocket(destinationId);
				stream = streams.get(destinationId);
			} else {
//				System.out.println("Reussing connection ... ");
			}
			
			try {
				stream.writeObject(message);
				stream.flush();
			} catch (IOException e) {
//				System.out.println("Retrying to create the socket after IOException...");
				createNewSocket(destinationId);
				stream.writeObject(message);
			}
		} catch (IOException e) {
			System.out.println("Couldn't send to destination :" + destinationId);
			e.printStackTrace();
		}
	}
	
	private void createNewSocket(String destinationId) throws IOException {
		String IP = getIP(destinationId);
		int port = getPort(destinationId);
		Socket socket = new Socket(IP, port);
		ObjectOutputStream stream = new ObjectOutputStream(socket.getOutputStream());
		streams.remove(destinationId);
		streams.put(destinationId, stream);		
	}


	public static String getIP(String ID) {
//		System.out.println("ID = "+ ID);
		return ID.split(PORT_IP_SEPERATOR)[0];
	}
	
	public static int getPort(String ID) {
		return Integer.parseInt(ID.split(PORT_IP_SEPERATOR)[1]);
	}
		
	public static String getID(String IP, int port) {
		return IP + PORT_IP_SEPERATOR + port;
	}
}
